const alioss = require('ali-oss');
const util = require('clf-util');
const debug = require('debug')('bbb-oss:oss');
const path = require('path');
const mkdirp = require('mkdirp');
const _ = require('lodash');
const storageReg = /(([\w-]+)="([^"]+)")/g
const OSSResult = require('./model/OSSResult')
module.exports = class BBBOSS {
	constructor(connectionStr, options) {
		debug('配置信息--connectionString:%O', connectionStr);
		debug('配置信息--options:%O', options);
		this.options = _.defaultsDeep({}, options);
		this.store = new alioss(connectionStr);
	}

	async exists(meetingID) {
		debug('exists:%s', meetingID);
		if (!id) {
			return false;
		}
		return this.store.list(
			{
				prefix: BBBOSS.joinPath(this.options.prefix, id),
				'max-keys': 1
			}).then(resStatus).then(function(rts) {
			return rts.objects;
		});
	}

	async isModified(name, etag) {
		let path = BBBOSS.joinPath(this.options.prefix, name);
		return this.store.head(path, { headers: { 'If-None-Match': etag } }).then(rts =>
			!(rts.res.status === 304 && rts.res.statusMessage === 'Not Modified')
		);
	}

	async head(name) {
		let path = BBBOSS.joinPath(this.options.prefix, name);
		return this.store.head(path).then(resStatus);
	}

	async push(name, filestream, opts) {
		let path = BBBOSS.joinPath(this.options.prefix, name);
		debug('push--path:%s,options:%O', path, opts);
		return this.store.putStream(path, filestream, opts).then(resStatus);
	}

	async restore(name, opts) {
		let path = BBBOSS.joinPath(this.options.prefix, name);
		debug('restore--path:%s,options:%O', path, opts);
		return this.store.restore(path, opts);
	}

	async pull(name, opts) {
		let path = BBBOSS.joinPath(this.options.prefix, name);
		let options = _.defaultsDeep({}, opts, { timeout: 120000 });
		debug('pull--path:%s,options:%O', path, options);
		return this.store.getStream(path, options).then(resStatus);
	}


	/**
	 * 获取文件，最大只可以获取1000个
	 * @param meetingID
	 * @param opts
	 * @return {Promise<*>}
	 */
	async pullRecording(meetingID, opts) {
		debug('pullRecording--获取录屏下的文件：%s', meetingID);
		let prefix = BBBOSS.joinPath(this.options.prefix, meetingID);
		let options = _.defaultsDeep({}, opts, { prefix }, this.options, { 'max-keys': 400 });
		return this.store.list(options).then(resStatus);
	}

	/**
	 * 获取所有文件
	 * @param meetingID
	 * @param opts
	 * @return {Promise<*>}
	 */
	async pullRecordingAll(meetingID, opts) {
		let cb = util.createPromiseCallback();
		let getall = async (marker, opts) => {
			let options = _.defaultsDeep({}, { marker }, opts);
			let allRts = await this.pullRecording(meetingID, options);
			let rRts = allRts.objects ? allRts.objects : [];
			debug('pullRecordingAll-获取到文件数：%s', rRts.length);
			if (allRts.nextMarker) {
				return rRts.concat(await getall(allRts.nextMarker, opts));
			}
			return rRts;
		};
		cb(null, await getall(null, opts));
		return cb.promise;
	}

	async groupRecording(opts) {
		debug('groupRecording-获取录屏IDs,options:%O', opts);
		let options = _.defaultsDeep({}, opts, this.options, { delimiter: '/', 'max-keys': 40 });
		return this.store.list(options).then(resStatus);
	}

	async groupRecordingAll(opts) {
		let cb = util.createPromiseCallback();
		let getall = async (marker, opts) => {
			let options = _.defaultsDeep({}, { marker }, opts);
			let rts = await this.groupRecording(options);
			let rRts = rts.prefixes ? rts.prefixes : [];
			debug('groupRecordingAll-获取到文件夹数：%s', rRts.length);
			if (rts.nextMarker) {
				return rRts.concat(await getall(rts.nextMarker, opts));
			}
			return rRts;
		};
		cb(null, await getall(null, opts));
		return cb.promise;
	}

	static joinPath(...args) {
		return _(args).flatMap(item => item ? item.split(new RegExp(`[\\${path.sep}\\\/]`)) : []).compact().value().join('/');
	}


	/**
	 * 是否已经请求过解冻操作
	 * @param fileName
	 * @returns {Promise<OSSResult>}
	 */
	async isRestored(fileName) {
		return this.head(fileName)
			.then(resStatus)
			.then(ret => {
				return new OSSResult(ret).storageStatus.isRequestRestore
			})
	}


	async restoreEx(fileName, time = 10) {
		return new Promise((resolve, reject) => {
			this.head(fileName)
				.then(resStatus)
				.then(ret => new OSSResult(ret))
				.then(ret => {
					let status = ret.storageStatus
					if (status.isStorage) {
						let recursion = (timeout) => {
							setTimeout(() => this.restoreEx(fileName, time).then(resolve).catch(reject), timeout)
						}
						if (!status.isRequestRestore) {
							return this.restore(fileName).then(() => recursion(1000 * time)).catch(reject)
						}
						if (status.restore_ing) {
							return recursion(1000 * time)
						} else if (status.restore_end) {
							resolve(fileName)
						} else {
							debug(`restoreEx:返回头未知的格式错误`)
							reject(fileName)
						}
					}
					resolve(fileName)
				})
		});
	}


};

function resStatus(rts) {
	if (rts.res.status !== 200) {
		return Promise.reject(rts);
	}
	return rts;
}
